﻿//////////////////////////////////////////////////////////////////
//
// Messages\TileImage.cs
//
// Copyright (c) 2012 Dan Pike.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using Interfaces;
using Ionic.Zlib;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Messages
{
   public class TileImage : Message<TileImage>, ITileImage
   {
      private string planetName_;
      private ILocation location_;
      private short[,] heights_;

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// 
      /// </summary>
      public TileImage()
         : base(ProtoBufTags.ITileImage)
      {
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// Implementation of ITileImage
      /// </summary>
      [ProtoMember((int)ProtoBufTags.TileImagePlanetName)]
      public string PlanetName
      {
         get { return planetName_; }
         set { planetName_ = value; }
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// Implementation of ITileImage
      /// 
      /// Note that we serialize this via a __hack property to avoid adding
      /// the ProtoInclude() nastiness to ILocation
      /// </summary>
      public ILocation Location
      {
         get { return location_; }
         set { location_ = value; }
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// Implementation of ITileImage
      /// </summary>
      public short[,] Heights
      {
         get { return heights_; }
         set { heights_ = value; }
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// ProtoBuf.Net has poor support for handle interfaces
      /// </summary>
      [ProtoMember((int)ProtoBufTags.TileImageLocation)]
      public float[] __hack_for_protobuf1
      {
         get
         {
            if (null != location_)
            {
               return new float[3] { location_.Longitude, location_.Latitude,
                  location_.Altitude };
            }
            return null;
         }
         set
         {
            location_ = Program.Loader.Create<ILocation>();
            location_.Longitude = value[0];
            location_.Latitude = value[1];
            location_.Altitude = value[2];
         }
      }

      ////////////////////////////////////////////////////////////////////////
      /// <summary>
      /// ProtoBuf.Net cannot handle multi-dimensional arrays.
      /// </summary>
      [ProtoMember((int)ProtoBufTags.TileImageHeights)]
      public byte[] __hack_for_protobuf2
      {
         get
         {
            if (null != heights_)
            {
               return new byte[1];

               int count = Const.tileWidth61 * Const.tileWidth61;
               MemoryStream stream = new MemoryStream(count);
               BinaryWriter binaryWriter = new BinaryWriter(stream);
               for (int index0 = 0; index0 < Const.tileWidth61; ++index0)
               {
                  for (int index1 = 0; index1 < Const.tileWidth61; ++index1)
                  {
                     binaryWriter.Write(heights_[index0, index1]);
                  }
               }
               //byte[] buffer = ZlibStream.CompressBuffer(stream.ToArray());
               byte[] buffer = stream.ToArray();
               return buffer;
            }
            return null;
         }
         set
         {
            heights_ = new short[Const.tileWidth61, Const.tileWidth61];
            return;
            
            int[] bounds = new int[] { heights_.GetLowerBound(0), heights_.GetUpperBound(0),
                  heights_.GetLowerBound(1), heights_.GetUpperBound(1) };

            //byte[] buffer = ZlibStream.UncompressBuffer(value);
            byte[] buffer = value;
            MemoryStream stream = new MemoryStream(buffer);
            BinaryReader binaryReader = new BinaryReader(stream);
            for (int index0 = bounds[0]; index0 <= bounds[1]; ++index0)
            {
               for (int index1 = bounds[2]; index1 <= bounds[3]; ++index1)
               {
                  heights_[index0, index1] = binaryReader.ReadInt16();
               }
            }
         }
      }
   }
}
